zix: serve the mounted certificate, drop upload, re-enable - #1303
Merged
Conversation
Contributor
|
👋 Heads up! This PR modifies the following frameworks:
|
MDA2AV
force-pushed
the
fix/zix-mounted-certs
branch
from
August 24, 2026 17:59
913f9c0 to
c8bcb8e
Compare
This was referenced Aug 24, 2026
Every zix Dockerfile generated its own self-signed Ed25519 certificate at image build and baked it at /etc/zix-tls; nothing in any of the five entries read the shared /certs mount. So every zix TLS listener -- json-tls, static-tls, baseline-h2, static-h2 and unary-grpc-tls -- signed its handshakes with an EC key while every other entry signs with the shared RSA-2048 pair. RSA-2048 signing is roughly 25x more expensive than an EC key, so those handshakes were cheaper than the ones they were being compared against. Point the four TLS path constants at /certs/server.crt and /certs/server.key and drop the cert-generation stage from all five Dockerfiles. zix-ws generated a certificate it never even copied into its runtime image; that goes too. validate.sh already mounts /certs whenever an entry subscribes to an h1-TLS, h2, h3 or grpc-tls profile, and the benchmark harness mounts it unconditionally, so nothing else has to change. Verified by rebuilding all five and re-validating each: zix 68 pass / 3 fail -> 70 pass / 1 fail zix-grpc 4 pass / 0 fail -> 9 pass / 0 fail zix-http2 23 pass / 2 fail -> 25 pass / 0 fail zix-ws 7 pass / 0 fail -> 7 pass / 0 fail zix-http3 no coverage exists for h3 -- see the validation PR The served certificate now matches certs/server.crt by fingerprint on every listener. zix's one remaining failure is POST /upload chunked, which is unrelated to TLS and is engine-level: zix.Http1 requires a chunked body to fit in a single receive buffer (.max_recv_buf, 8 KiB) while the Content-Length path drains correctly to 20 MB. Raising that buffer fixes the check but it is per-connection memory, so it is an upstream fix rather than an entry one.
With the certificate fix the only remaining failure was POST /upload chunked, and that one is not the entry's to fix: zix.Http1 requires a chunked body to fit in a single receive buffer (.max_recv_buf, 8 KiB) while the Content-Length path drains correctly to 20 MB. Measured: chunked succeeds to exactly 8192 bytes, drops the connection at the boundary, and returns 413 from 8193 up; raising max_recv_buf to 256 K makes 112 KB pass and 1 MB still fail. That buffer is per-connection, so sizing it to the 24 MB max_request_body is not viable at these connection counts. Unsubscribing is the honest option -- the alternative is raising the buffer far enough to clear the validator's probe, which games the check rather than fixing the engine, and costs memory score while doing it. upload is engineScored=False, so zix is an engine entry that loses no score by dropping it. The /upload handler stays in the source; it works correctly for Content-Length bodies and is simply no longer a subscribed profile. zix now validates clean and comes back on: 66 passed, 0 failed.
MDA2AV
force-pushed
the
fix/zix-mounted-certs
branch
from
August 24, 2026 18:47
c8bcb8e to
a11c1c1
Compare
Owner
Author
|
/benchmark-multiple --save |
Contributor
|
👋 Benchmark request received. A collaborator will review and approve the run. |
Contributor
Benchmark ResultsFrameworks: 5 | Test: ✅
|
| Test | Conn | RPS | CPU | Mem | Δ RPS | Δ Mem |
|---|---|---|---|---|---|---|
| baseline | 512 | 4,188,550 | 6361.8% | 133MiB | ~0% | ~0% |
| baseline | 4096 | 4,442,329 | 6427.0% | 194MiB | ~0% | ~0% |
| pipelined | 512 | 56,503,100 | 6436.5% | 132MiB | ~0% | ~0% |
| pipelined | 4096 | 58,761,616 | 6408.9% | 193MiB | ~0% | ~0% |
| limited-conn | 512 | 2,683,418 | 5513.5% | 131MiB | ~0% | ~0% |
| limited-conn | 4096 | 2,708,192 | 5826.4% | 236MiB | ~0% | ~0% |
| json | 4096 | 2,325,200 | 6534.2% | 287MiB | ~0% | ~0% |
| json-comp | 512 | 955,775 | 6059.4% | 132MiB | ~0% | ~0% |
| json-comp | 4096 | 1,046,581 | 6825.8% | 212MiB | ~0% | ~0% |
| json-comp | 16384 | 1,018,808 | 6533.4% | 527MiB | ~0% | ~0% |
| json-tls | 4096 | 1,845,248 | 5396.1% | 280MiB | ~0% | ~0% |
| api-4 | 256 | 62,678 | 199.8% | 40MiB | ~0% | ~0% |
| api-16 | 1024 | 247,788 | 1097.0% | 132MiB | ~0% | ~0% |
| static | 1024 | 222,558 | 6658.0% | 456MiB | ~0% | ~0% |
| static | 4096 | 233,973 | 6617.6% | 1.4GiB | ~0% | ~0% |
| static | 6800 | 231,573 | 6568.0% | 2.3GiB | ~0% | ~0% |
| static-tls | 1024 | 339,689 | 6603.4% | 228MiB | ~0% | ~0% |
| static-tls | 4096 | 314,396 | 6492.3% | 543MiB | ~0% | ~0% |
| static-tls | 6800 | 300,828 | 6496.8% | 841MiB | ~0% | ~0% |
| async-db | 1024 | 400,444 | 3183.3% | 337MiB | ~0% | ~0% |
| crud | 4096 | 823,462 | 3213.5% | 387MiB | ~0% | ~0% |
✅ zix-grpc
| Test | Conn | RPS | CPU | Mem | Δ RPS | Δ Mem |
|---|---|---|---|---|---|---|
| unary-grpc | 256 | 7,000,555 | 2791.2% | 180MiB | ~0% | ~0% |
| unary-grpc | 1024 | 7,030,197 | 2904.3% | 206MiB | ~0% | ~0% |
| unary-grpc-tls | 256 | 6,962,147 | 2903.7% | 201MiB | ~0% | ~0% |
| unary-grpc-tls | 1024 | 6,781,146 | 2877.7% | 318MiB | ~0% | ~0% |
✅ zix-http2
| Test | Conn | RPS | CPU | Mem | Δ RPS | Δ Mem |
|---|---|---|---|---|---|---|
| baseline-h2 | 256 | 14,076,613 | 4108.2% | 120MiB | ~0% | ~0% |
| baseline-h2 | 1024 | 14,090,534 | 4164.7% | 216MiB | ~0% | ~0% |
| static-h2 | 256 | 1,692,045 | 5935.6% | 217MiB | ~0% | ~0% |
| static-h2 | 1024 | 1,650,640 | 6431.3% | 563MiB | ~0% | ~0% |
| baseline-h2c | 256 | 13,956,726 | 3999.4% | 106MiB | ~0% | ~0% |
| baseline-h2c | 1024 | 14,569,901 | 4171.5% | 126MiB | ~0% | ~0% |
| baseline-h2c | 4096 | 13,411,078 | 3900.5% | 220MiB | ~0% | ~0% |
| json-h2c | 1024 | 6,821,589 | 3891.6% | 177MiB | ~0% | ~0% |
| json-h2c | 4096 | 6,746,440 | 4204.8% | 425MiB | ~0% | ~0% |
✅ zix-http3
| Test | Conn | RPS | CPU | Mem | Δ RPS | Δ Mem |
|---|---|---|---|---|---|---|
| baseline-h3 | 64 | 9,086,240 | 1281.9% | 412MiB | ~0% | ~0% |
| static-h3 | 64 | 595,586 | 3297.5% | 412MiB | ~0% | ~0% |
✅ zix-ws
| Test | Conn | RPS | CPU | Mem | Δ RPS | Δ Mem |
|---|---|---|---|---|---|---|
| echo-ws | 512 | 4,277,156 | 6402.6% | 206MiB | ~0% | ~0% |
| echo-ws | 4096 | 4,469,914 | 6419.3% | 251MiB | ~0% | ~0% |
| echo-ws | 16384 | 4,254,843 | 6408.1% | 487MiB | ~0% | ~0% |
| echo-ws-pipeline | 512 | 60,193,061 | 6381.1% | 211MiB | ~0% | ~0% |
| echo-ws-pipeline | 4096 | 66,037,087 | 6239.8% | 248MiB | ~0% | ~0% |
| echo-ws-pipeline | 16384 | 61,907,676 | 6152.3% | 497MiB | ~0% | ~0% |
| echo-ws-limited | 512 | 2,254,504 | 5259.0% | 176MiB | ~0% | ~0% |
| echo-ws-limited | 4096 | 2,566,106 | 5761.4% | 280MiB | ~0% | ~0% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every zix Dockerfile generated its own self-signed Ed25519 certificate at image build and baked it at
/etc/zix-tls:Nothing in any of the five entries read the shared
/certsmount. So every zix TLS listener —json-tls,static-tls,baseline-h2,static-h2andunary-grpc-tls— signed its handshakes with an EC key while every other entry signs with the shared RSA-2048 pair. RSA-2048 signing is roughly 25× more expensive, so those handshakes were cheaper than the ones they were being compared against.1. Serve the mounted certificate
Point the four TLS path constants at
/certs/server.crt//certs/server.keyand drop the cert-generation stage from all five Dockerfiles.zix-wsgenerated a certificate it never even copied into its runtime image — that goes too.No harness change needed:
validate.shalready mounts/certsfor any h1-TLS, h2, h3 or grpc-tls subscriber, andframework.shmounts it unconditionally for benchmarks.zixzix-grpczix-http2zix-wszix-http3The served certificate now matches
certs/server.crtby fingerprint (6E:00:1C:1F:…) on every listener.zix-grpcgains 5 checks because its TLS port had no posture probe at all — that gap is closed in #1304, and it passes there only because of this fix.2. Drop
upload, re-enable the entryThat left one failure,
POST /upload chunked, and it is not the entry's to fix.zix.Http1requires a chunked body to fit in a single receive buffer (.max_recv_buf, 8 KiB) while the Content-Length path drains correctly to 20 MB. Measured:Raising
max_recv_bufto 256 K makes 112 KB pass and 1 MB still fail, confirming that buffer is the binding constraint. It is per-connection, so sizing it to the 24 MBmax_request_bodyis not viable at these connection counts — and raising it just far enough to clear the validator's probe would game the check rather than fix the engine, while costing memory score.uploadisengineScored=False, so zix is anengineentry that loses no score by unsubscribing. The/uploadhandler stays in the source; it works correctly for Content-Length bodies and is simply no longer a subscribed profile.zixnow validates clean — 66 passed, 0 failed — andenabledgoes back totrue.Note on the result file
site/data/results/zix.jsondoes not exist on main; #1291 dropped it along with the entry. This PR does not restore numbers — #1221 (prothegee) is the re-entry that does, and it currently conflicts because of that same deletion and needs a rebase.🤖 Generated with Claude Code